package blue.global.base;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

/**
 * 通用Dao
 * 
 * @author zhnegj
 * @since 2009-01-20 1.0
 */
public abstract class BaseDao<T, ID extends Serializable> implements IPageable<T>
{
	private Class<T> persistentClass;
	protected HibernateTemplate hibernateTemplate;

	@SuppressWarnings("unchecked")
	public BaseDao()
	{
		this.persistentClass = (Class<T>)((ParameterizedType)getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}

	/**
	 * 把对象持久(添加)到数据库中
	 * 
	 * @param object 对象
	 */
	public void save(T object)
	{
		hibernateTemplate.save(object);
	}

	/**
	 * 把对象从数据库中删除
	 * 
	 * @param object 对象
	 */
	public void delete(T object)
	{
		hibernateTemplate.delete(object);
	}

	/**
	 * 把对象更新到数据库
	 * 
	 * @param object 对象
	 */
	public void update(T object)
	{
		hibernateTemplate.update(object);
	}

	/**
	 * 从数据库中加载一个对象(立即加载)
	 * 
	 * @param id 对象的主键，必须实现 java.io.Serializable 接口
	 * @return 一个对象，不存在返回 null
	 */
	@SuppressWarnings("unchecked")
	public T get(ID id)
	{
		return (T)hibernateTemplate.get(persistentClass, id);
	}

	/**
	 * 从数据库中加载一个对象的代理(延迟加载)
	 * 
	 * @param id 对象的主键，必须实现 java.io.Serializable 接口
	 * @return 一个对象的代理
	 * @throws HibernateException 如果对象不存在抛出该异常
	 */
	@SuppressWarnings("unchecked")
	public T load(ID id) throws HibernateException
	{
		return (T)hibernateTemplate.load(persistentClass, id);
	}
	
	/**
	 * 从 Hibernate 的缓存中移除对象
	 * 
	 * @param object 对象
	 */
	public void evict(T object)
	{
		hibernateTemplate.evict(object);
	}
	
	/**
	 * 初始化一个代理对象
	 * 
	 * @param proxy 代理对象
	 */
	public void initialize(Object proxy)
	{
		hibernateTemplate.initialize(proxy);
	}
	
	/**
	 * 列出在数据库中的所有对象，不分页
	 * 
	 * @param entity 查询参数
	 * @return 对象列表
	 */
	@SuppressWarnings("unchecked")
	public List<T> list(T entity)
	{
		StringBuilder hql = new StringBuilder(String.format(
				"SELECT a FROM %s a WHERE 1=1", persistentClass.getSimpleName()));
		List<Object> params = new ArrayList<Object>();
		params = this.queryCore(hql, params, entity);
		if (params.size() == 0)
			return hibernateTemplate.find(hql.toString());
		else
			return hibernateTemplate.find(hql.toString(), params.toArray());
	}
	
	@Override
	public Page<T> list(T entity, Page<T> page)
	{
		int rows = this.getRows(entity);
		page.setRows(rows);
		List<T> objectList = this.list(entity, page.getStartRowNo(), page.getSize());
		page.setObjectList(objectList);
		
		return page;
	}

	@Override
	public int getRows(T entity)
	{
		StringBuilder hql = new StringBuilder(String.format(
				"SELECT COUNT(*) FROM %s a WHERE 1=1", persistentClass.getSimpleName()));
		long rows = 0;
		List<Object> params = new ArrayList<Object>();
		params = this.queryCore(hql, params, entity);
		if (params.size() == 0)
		{
			rows = (Long)hibernateTemplate.find(hql.toString()).get(0);
		}
		else
		{
			rows = (Long)hibernateTemplate.find(hql.toString(), params.toArray()).get(0);
		}
		return (int)rows;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> list(T entity, final int start, final int size) throws IllegalArgumentException
	{
		if (start < 0 || size < 1)
			throw new IllegalArgumentException("起始行号不能小于 0 或最多记录数不能小于 1");
		
		final StringBuilder hql = new StringBuilder(String.format(
				"SELECT a FROM %s a WHERE 1=1", persistentClass.getSimpleName()));
		final List<Object> params = this.queryCore(hql, new ArrayList<Object>(), entity);
		
		return hibernateTemplate.executeFind(new HibernateCallback()
		{
			@Override
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException
			{
				Query query = session.createQuery(hql.toString());
				
				for (int i = 0; i < params.size(); i++)
				{
					query.setParameter(i, params.get(i));
				}
				
				query.setFirstResult(start);
				query.setMaxResults(size);
				return query.list();
			}
			
		});
	}
	
	/**
	 * <p>创建查询 WHERE 子句，<b>子类通过覆盖该方法来自定义查询</b></p>
	 * <b>注：父类该方法并没作任何查询
	 * 
	 * @param entity 查询参数
	 * @return 查询 WHERE 子句
	 */
	protected List<Object> queryCore(StringBuilder hql, List<Object> paramList, T entity)
	{
		return paramList;
	}

	public void setHibernateTemplate(HibernateTemplate hibernateTemplate)
	{
		this.hibernateTemplate = hibernateTemplate;
	}

}
